package com.ljx.video.mq.consumer;

import cn.hutool.core.util.RuntimeUtil;
import com.ljx.video.constant.MyConstant;
import com.ljx.video.domain.dto.VideoTransCodingDto;
import com.ljx.video.domain.entity.File;
import com.ljx.video.mq.constant.RabbitMqConstant;
import com.ljx.video.service.VideoService;
import com.ljx.video.util.FfmpegUtil;
import com.ljx.video.util.FileUtil;
import com.ljx.video.util.MinioUtil;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2025-01-18  14:47
 */
@Component
public class VideoConsumer {

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private FfmpegUtil ffmpegUtil;

    @Autowired
    private VideoService videoService;

//    @RabbitListener(bindings = @QueueBinding(
//            value = @Queue(name = RabbitMqConstant.TRANS_QUEUE, durable = "true"),
//            exchange = @Exchange(name = RabbitMqConstant.TRANS_EXCHANGE, type = ExchangeTypes.TOPIC),
//            key = RabbitMqConstant.TRANS_KEY
//    ))
//    public void listenTransCoding(VideoTransCodingDto dto){
//        File file = videoService.getById(dto.getFileId());
//        InputStream videoStream = minioUtil.getVideoStream(file.getFileMd5(), file.getFilename());
//        Path tempFile = minioUtil.createTempFile(System.getProperty("user.dir") + "\\temp\\" + file.getFileMd5());
//
//        try {
//            // 构建FFmpeg命令
//            ProcessBuilder processBuilder = new ProcessBuilder(
//                    "E:/ffmpeg/ffmpeg.exe",
//                    "-i", "pipe:0", // 从标准输入读取数据
//                    "-codec:", "copy", // 使用原始编解码器
//                    "-start_number", "0", // 分片文件从0开始编号
//                    "-hls_time", "10", // 每个分片的时长（秒）
//                    "-hls_list_size", "0", // 保留所有分片
//                    "-f", "hls", // 输出格式为HLS
//                    tempFile.resolve("output.m3u8").toString()
//            );
//            Process process = processBuilder.start();
//
//            long count = 0;
//            // 将输入流写入FFmpeg的标准输入
//            try (OutputStream ffmpegInputStream = process.getOutputStream()) {
//                int bytesRead;
//                byte[] buffer = new byte[1024 * 1024];
//                while ((bytesRead = videoStream.read(buffer)) != -1) {
//                    ffmpegInputStream.write(buffer, 0, bytesRead);
//                    count += bytesRead;
//                    System.out.println("写入了 " + bytesRead + " 字节，一共" + count + "字节");
//                }
//                ffmpegInputStream.flush();
//            }
//
//
//            InputStream errorStream = process.getErrorStream();
//            BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
//            String line;
//            while ((line = reader.readLine()) != null) {
//                System.err.println(line);
//            }
//
//            // 等待FFmpeg完成
//            int exitCode = process.waitFor();
//            if (exitCode != 0) {
//                throw new RuntimeException("FFmpeg转码失败，退出码: " + exitCode);
//            }
//            System.out.println(tempFile);
//
//
////            // 将视频流输入 FFmpeg 的标准输入
////            try (OutputStream ffmpegInputStream = process.getOutputStream()) {
////                int bytesRead;
////                byte[] buffer = new byte[1024 * 1024];
////                while ((bytesRead = videoStream.read(buffer)) != -1) {
////                    ffmpegInputStream.write(buffer, 0, bytesRead);
////                }
////                ffmpegInputStream.flush();
////            }
////            ByteArrayOutputStream m3u8OutputStream = new ByteArrayOutputStream();
////            ByteArrayOutputStream tsOutputStream = new ByteArrayOutputStream();
////            // 读取 FFmpeg 的输出流并传递到 M3U8 和 TS 输出流
////            try (BufferedInputStream m3u8Stream = new BufferedInputStream(process.getInputStream());
////                 BufferedInputStream tsStream = new BufferedInputStream(process.getErrorStream())) {
////                // 处理 M3U8 数据流
////                new Thread(() -> {
////                    getOutputStream(m3u8Stream, m3u8OutputStream);
////                }).start();
////                // 处理 TS 数据流
////                new Thread(() -> {
////                    getOutputStream(tsStream, tsOutputStream);
////                }).start();
////            }
////            // 将 M3U8 文件上传到 MinIO
////            try (InputStream m3u8InputStream = new ByteArrayInputStream(m3u8OutputStream.toByteArray())) {
////                minioUtil.uploadM3u8ToMinio(m3u8InputStream, file.getFileMd5());
////            }
////            // 将 TS 文件上传到 MinIO
////            try (InputStream tsInputStream = new ByteArrayInputStream(tsOutputStream.toByteArray())) {
////                // 这里假设 TS 文件是多个，需要按顺序上传
////                int segmentCount = 1;
////                byte[] buffer = new byte[1024];
////                int bytesRead;
////                while ((bytesRead = tsInputStream.read(buffer)) != -1) {
////                    // 上传每个 TS 文件
////                    ByteArrayInputStream tsSegmentInputStream = new ByteArrayInputStream(buffer, 0, bytesRead);
////                    minioUtil.uploadM3u8TsToMinio(tsSegmentInputStream, file.getFileMd5(), segmentCount ++);
////                }
////            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                if (videoStream != null) {
//                    videoStream.close();
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//
//    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = RabbitMqConstant.TRANS_QUEUE, durable = "true"),
            exchange = @Exchange(name = RabbitMqConstant.TRANS_EXCHANGE, type = ExchangeTypes.TOPIC),
            key = RabbitMqConstant.TRANS_KEY
    ))
    public void listenTransCoding(VideoTransCodingDto dto) {
        File file = videoService.getById(dto.getFileId());
        Path tempFile = minioUtil.createTempFile(System.getProperty("user.dir") + "\\file\\" + file.getFileMd5());
        // 检查视频文件编码并转转码
        checkVideoCodecAndConvert(tempFile, file);
        // 生成 index.ts 文件
        buildIndexTs(tempFile, file);
        // 切割 index.ts 并生成索引
        cutIndexTs(tempFile);
        // 删除 index.ts 文件
        FileUtil.removeFile(tempFile + "/index.ts");
    }

    private void cutIndexTs(Path tempFile) {
        try {
            Path path = Paths.get(tempFile + "/ts");
            if (!Files.exists(path)) {
                Files.createDirectories(path);
            }
            ProcessBuilder processBuilder = ffmpegUtil.cutIndexTsProcessBuilder(tempFile + "/index.ts", tempFile + "/index.m3u8", tempFile + "/ts/%4d.ts");
            RuntimeUtil.execForStr(String.join(" ", processBuilder.command()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void buildIndexTs(Path tempFile, File file) {
        try {
            ProcessBuilder processBuilder = ffmpegUtil.getIndexTsProcessBuilder(tempFile + "/" + file.getFilename(), tempFile + "/index.ts");
            RuntimeUtil.execForStr(String.join(" ", processBuilder.command()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void checkVideoCodecAndConvert(Path tempFile, File file) {
        try {
            ProcessBuilder processBuilder = ffmpegUtil.getVideoCodecProcessBuilder(tempFile + "/" + file.getFilename());
            String result = RuntimeUtil.execForStr(String.join(" ", processBuilder.command()));
            int i = result.indexOf("=");
            StringBuffer codec = new StringBuffer();
            for(; i < result.length(); i++) {
                if (result.charAt(i) == '[') {
                    break;
                }
                codec.append(result.charAt(i));
            }
            if (!codec.equals(MyConstant.HEVC)) {
                return;
            }
            processBuilder = ffmpegUtil.convertVideoCodecProcessBuilder(tempFile + "/" + file.getFilename(), tempFile + "/trans_" + file.getFilename());
            RuntimeUtil.execForStr(processBuilder.toString());
            FileUtil.removeFile(tempFile + "/" + file.getFilename());
            FileUtil.renameFile(tempFile + "/trans_" + file.getFilename(), tempFile + "/" + file.getFilename());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void getOutputStream(BufferedInputStream m3u8Stream, ByteArrayOutputStream m3u8OutputStream ) {
        try {
            byte[] m3u8Buffer = new byte[1024];
            int m3u8BytesRead;
            while ((m3u8BytesRead = m3u8Stream.read(m3u8Buffer)) != -1) {
                m3u8OutputStream.write(m3u8Buffer, 0, m3u8BytesRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
